/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  constructor(executor) {
    try {
      // 执行寄存器，将promise自身的resolve和reject方法作为执行器函数的回调函数
      executor(this.resolve, this.reject)
    } catch (error) {
      // 如果执行执行器函数过程中异常，则调用自身reject方法
      this.reject(error.message)
    }
  }

  _status = PENDING; // promise状态 默认为等待
  _result = undefined; // 成功的结果
  _reason = undefined; // 失败的结果
  _succList = [] // 成功回调队列
  _failList = [] // 失败回调队列
  _finallyList = []

  resolve = (result) => {
    // 状态不可逆
    if (this._status !== PENDING) return
    this._result = result // 记录执行结果
    this._status = FULFILLED // 变更状态
    while (this._succList.length) { // 执行回调队列中的函数
      this._succList.pop()(this._result)
    }
    while (this._finallyList.length) { // 执行回调队列中的函数
      this._finallyList.pop()()
    }
  }
  reject = (reason) => {
    // 状态不可逆
    if (this._status !== PENDING) return
    this._reason = reason
    this._status = REJECTED
    while (this._failList.length) {
      this._failList.pop()(new Error(this._reason))
    }
  }
  then (succ, fail) {
    succ = succ || (value => value)
    fail = fail || (reason => { throw new Error(reason) })
    if (this._status === FULFILLED) {
      try {
        return greneralPromise(succ(this._result))
      } catch (error) {
        return new MyPromise((reslove, reject) => { reject(error.message) })
      }
    } else if (this._status === REJECTED) { // 同成功逻辑
      try {
        return greneralPromise(fail(new Error(this._reason)))
      } catch (error) {
        return new MyPromise((reslove, reject) => { reject(error.message) })
      }
    } else {
      // 处理异步的情况，将resolve/reject封装到回调函数中，push到回调队列中。等待promise执行完成后再调用
      return new MyPromise((resolve, reject) => { // 返回Promise对象
        this._succList.push((value) => {
          try {
            const result = succ(value)
            if (result instanceof MyPromise) {
              result.then(result => resolve(result), error => reject(error))
            } else {
              resolve(result) // 将succ和resolve的调用封装
            }

          } catch (error) {
            reject(error.message)
          }
        })
        this._failList.push((reason) => {
          try {
            const result = fail(reason)
            if (result instanceof MyPromise) {
              result.then(result => resolve(result), error => reject(error))
            } else {
              fail(result)
            }
          } catch (error) {
            reject(error.message)
          }
        })
      })
    }
  }
  catch (fail) {
    return this.then(undefined, fail)
  }

  finally (handler) {
    return this.then(result => {
      handler(result)
    }, reason => {
      handler(new Error(reason))
    })
  }

  static all (args) {
    return new MyPromise((resolve, reject) => {
      const results = []
      let finishedCount = 0
      args.forEach((promise, index) => {
        promise.then(result => {
          results[index] = result
          finishedCount++
          if (finishedCount === args.length) {
            resolve(results)
          }
        }, (reason) => {
          reject(reason)
        })
      })
    })
  }

  static race (args) {
    return new MyPromise((resolve, reject) => {
      const results = []
      let finishedCount = 0
      args.forEach((promise, index) => {
        promise.then(result => {
          results[index] = result
          finishedCount++
          if (finishedCount === 1) {
            resolve(results)
          }
        }, (reason) => {
          reject(reason)
        })
      })
    })
  }

  static resolve (value) {
    if (value instanceof MyPromise) return value
    return new MyPromise((resolve) => resolve(value))
  }
}

function greneralPromise (result) {
  if (result instanceof MyPromise) {
    return result
  } else {
    return new MyPromise((resolve, reject) => {
      resolve(result)
    })
  }
}

module.exports = MyPromise